package com.httam.taxiSmart;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import javax.net.ssl.HttpsURLConnection;

import org.apache.http.auth.MalformedChallengeException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.httam.taxiSmart.Util.ConnectionDetector;

/**
 * This class calculator manual cost
 * 
 * @author Sparkle (' - ')
 * 
 */

public class CostActivity extends FragmentActivity implements
		OnItemSelectedListener {

	// Handle widgets UI
	private GoogleMap mMap;
	MarkerOptions markerOptions;
	private Spinner spnHangTaxi;
	private Spinner spnLoaiXe;
	TextView txtDistance_time;
	TextView txtCost;
	private AutoCompleteTextView auto_from;
	private AutoCompleteTextView auto_to;
	LatLng latLng;
	ArrayList<LatLng> mMarkerPoints;

	// flag for Internet connection status
	Boolean isInternetPresent = false;

	// Connection detector class
	com.httam.taxiSmart.Util.ConnectionDetector connState;

	// SQLite database
	SQLiteDatabase sqlitedB;

	PlacesAutoCompleteAdapter mPlaceAutoAdapter;

	String HangTaxi = null;
	ArrayList<String> arrListTaxi = null;
	ArrayList<String> arrListLoaiXe = null;

	private static final String LOG_TAG = "TaxiSmart Error";

	private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place";
	private static final String TYPE_AUTOCOMPLETE = "/autocomplete";
	private static final String OUT_JSON = "/json";

	private static final String API_KEY = "AIzaSyCZJC42i5lutHbakdpZzGxShHNmfTa_X_I";

	private ArrayList<String> resultList;

	private ArrayList<String> autocomplete(String input)
			throws MalformedChallengeException {

		ArrayList<String> resultList = null;

		HttpURLConnection conn = null;
		StringBuilder jsonResults = new StringBuilder();
		try {
			StringBuilder sb = new StringBuilder(PLACES_API_BASE
					+ TYPE_AUTOCOMPLETE + OUT_JSON);
			sb.append("?input=" + URLEncoder.encode(input, "utf-8"));
			sb.append("&types=geocode");
			sb.append("&components=country:VN");
			sb.append("&radius=500");
			sb.append("language=vi");
			sb.append("&sensor=true&key=" + API_KEY);

			URL url = new URL(sb.toString());
			conn = (HttpURLConnection) url.openConnection();
			InputStreamReader in = new InputStreamReader(conn.getInputStream());

			// Load the results into a StringBuilder
			int read;
			char[] buff = new char[1024];
			while ((read = in.read(buff)) != -1) {
				jsonResults.append(buff, 0, read);
			}
		} catch (IOException e) {
			Log.e(LOG_TAG, "Error connecting to Places API", e);
			return resultList;
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}

		try {
			// Create a JSON object hierachy from the results
			JSONObject jsonObj = new JSONObject(jsonResults.toString());
			JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

			// Extract the Place descriptions from the results
			resultList = new ArrayList<String>(predsJsonArray.length());
			for (int i = 0; i < predsJsonArray.length(); i++) {
				resultList.add(predsJsonArray.getJSONObject(i).getString(
						"description"));
			}
		} catch (JSONException e) {
			Log.e(LOG_TAG, "Cannot process JSON results", e);
		}

		return resultList;
	}

	private class PlacesAutoCompleteAdapter extends ArrayAdapter<String>
			implements Filterable {

		public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
			super(context, textViewResourceId);
		}

		@Override
		public int getCount() {

			return resultList.size();
		}

		@Override
		public String getItem(int position) {

			return resultList.get(position);
		}

		@Override
		public Filter getFilter() {

			Filter filter = new Filter() {

				@Override
				protected void publishResults(CharSequence constraint,
						FilterResults results) {
					if (results != null && results.count > 0) {
						notifyDataSetChanged();
					} else {
						notifyDataSetInvalidated();
					}
				}

				@Override
				protected FilterResults performFiltering(CharSequence constraint) {

					FilterResults filterResults = new FilterResults();
					if (constraint != null) {
						// Retrive the autocomplete results
						try {
							resultList = autocomplete(constraint.toString());
						} catch (MalformedChallengeException e) {

							e.printStackTrace();
						}

						// Assign the data to the FilterResults
						filterResults.values = resultList;
						filterResults.count = resultList.size();
					}

					return filterResults;
				}
			};

			return filter;
		}

	}

	/**
	 * Initializing the activity
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_cost);

		// creating connection detector class instance
		connState = new ConnectionDetector(getApplicationContext());

		// get internet status
		isInternetPresent = connState.isConnectingToInternet();

		// check for Internet status
		if (isInternetPresent) {
			Toast.makeText(CostActivity.this, "You have internet connection",
					Toast.LENGTH_LONG).show();
		} else {
			// Show notify user to know
			Toast.makeText(CostActivity.this,
					"You don't have internet connection", Toast.LENGTH_LONG)
					.show();
		}

		spnHangTaxi = (Spinner) findViewById(R.id.spnHangTaxiCost);
		spnLoaiXe = (Spinner) findViewById(R.id.spnLoaiXeCost);

		// Load sqlite database to spinner
		sqlitedB = openOrCreateDatabase(MainActivity.pathSQLite, MODE_PRIVATE,
				null);
		Cursor curSor = sqlitedB.query("HangTaxi", null, null, null, null,
				null, null);
		arrListTaxi = new ArrayList<String>();
		curSor.moveToFirst();
		while (!curSor.isAfterLast()) {
			String data = curSor.getString(1);
			arrListTaxi.add(data);
			curSor.moveToNext();
		}
		curSor.close();

		ArrayAdapter<String> adapterTaxi = new ArrayAdapter<String>(this,
				android.R.layout.simple_spinner_item, arrListTaxi);
		adapterTaxi
				.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spnHangTaxi.setAdapter(adapterTaxi);
		spnHangTaxi.setOnItemSelectedListener(this);

		txtDistance_time = (TextView) findViewById(R.id.txtQuangDuong);
		txtCost = (TextView) findViewById(R.id.txtGiaCuoc);

		SupportMapFragment mf = (SupportMapFragment) getSupportFragmentManager()
				.findFragmentById(R.id.costmap);
		mMap = mf.getMap();

		mMarkerPoints = new ArrayList<LatLng>();

		auto_from = (AutoCompleteTextView) findViewById(R.id.auto_diemdau);
		auto_to = (AutoCompleteTextView) findViewById(R.id.auto_diemcuoi);
		mPlaceAutoAdapter = new PlacesAutoCompleteAdapter(CostActivity.this,
				R.layout.list_item);
		auto_from.setAdapter(mPlaceAutoAdapter);
		auto_to.setAdapter(mPlaceAutoAdapter);
		auto_from.setThreshold(1);
		auto_to.setThreshold(1);

		// Set event listener for origin address
		auto_from.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {

				String origin = auto_from.getText().toString();
				String destination = auto_to.getText().toString();

				if (destination.isEmpty()) {
					auto_to.requestFocus();
				} else {
					direction2Point(origin, destination);
				}
			}

		});

		// Set event listener for destination address
		auto_to.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {

				String destination = auto_to.getText().toString();
				String origin = auto_from.getText().toString();

				if (origin.isEmpty()) {
					auto_from.requestFocus();
				} else {
					direction2Point(origin, destination);
				}
			}

		});

	}

	@Override
	protected void onResume() {

		super.onResume();
	}

	private void direction2Point(String source, String dest) {

		mMap.clear();
		mMarkerPoints.clear();
		LatLng origin = null;
		LatLng destination = null;

		try {
			origin = getCordinates(source);
			if (origin == null) {
				mMap.clear();
			}
			drawMarker(origin, source);

		} catch (IOException e) {

			Log.e("Error origin", e.getMessage());
		}

		try {
			destination = getCordinates(dest);
			if (destination == null)
				mMap.clear();
			drawMarker(destination, dest);

		} catch (IOException e) {

			Log.e("Error destination", e.getMessage());
		}

		LatLngBounds.Builder builder = new LatLngBounds.Builder();
		builder.include(origin);
		builder.include(destination);
		LatLngBounds bounds = builder.build();
		mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 20));

		// Getting URL to the Google Directions API
		String url = getDirectionsUrl(origin, destination);

		DownloadTask downloadTask = new DownloadTask();

		// Start downloading json data from Google Directions API
		downloadTask.execute(url);

	}

	/**
	 * This method draw markerOptions for location
	 * 
	 * @param point
	 */

	private void drawMarker(LatLng point, String address) {

		mMarkerPoints.add(point);

		// Create an instance of MarkerOptions
		MarkerOptions markerOptions = new MarkerOptions();

		// Setting position of the marker
		markerOptions.position(point);
		markerOptions.title(address);

		if (mMarkerPoints.size() == 1) {
			markerOptions.icon(BitmapDescriptorFactory
					.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
		} else if (mMarkerPoints.size() == 2) {
			markerOptions.icon(BitmapDescriptorFactory.defaultMarker());
		}

		// Add markers to google map
		mMap.addMarker(markerOptions);

	}

	/**
	 * Get direction between two location using Google Direction API
	 * 
	 */
	private String getDirectionsUrl(LatLng origin, LatLng destination) {

		// Origin of route
		String str_origin = "origin=" + origin.latitude + ","
				+ origin.longitude;

		// Destination of route
		String str_dest = "destination=" + destination.latitude + ","
				+ destination.longitude;

		// Sensor enabled
		String sensor = "sensor=true";

		// Building the parameters to the web service
		String parameters = str_origin + "&" + str_dest + "&" + sensor;

		// Output format
		String output = "json";

		// Building the url to the web service
		String url = "https://maps.googleapis.com/maps/api/directions/"
				+ output + "?" + parameters;

		return url;
	}

	/**
	 * Method download json from url
	 */
	private String downloadUrl(String strUrl) throws IOException {
		String data = "";
		InputStream iStream = null;
		HttpsURLConnection urlConnection = null;
		try {
			URL url = new URL(strUrl);

			// Creating an http connection to communicate with url
			urlConnection = (HttpsURLConnection) url.openConnection();

			// Connecting to url
			urlConnection.connect();

			// Reading data from url
			iStream = urlConnection.getInputStream();

			BufferedReader br = new BufferedReader(new InputStreamReader(
					iStream));

			StringBuffer sb = new StringBuffer();

			String line = "";
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}

			data = sb.toString();

			br.close();

		} catch (Exception e) {
			Log.d("Exception while downloading url", e.toString());
		} finally {
			iStream.close();
			urlConnection.disconnect();
		}
		return data;
	}

	/**
	 * Geocode address to Latitude
	 * 
	 * @author Sparkle (' - ')
	 * @throws IOException
	 * 
	 */
	private LatLng getCordinates(String Location) throws IOException {
		Geocoder geocoder = new Geocoder(this, new Locale("vi"));

		LatLng lat = null;
		// Place your latitude and longitude
		List<Address> addresses = geocoder.getFromLocationName(Location, 1);

		Address fetchAddress = addresses.get(0);

		double origin = fetchAddress.getLatitude();
		double destination = fetchAddress.getLongitude();

		lat = new LatLng(origin, destination);

		return lat;

	}

	/**
	 * Method downloadtask run background
	 * 
	 * @author Sparkle (' - ')
	 * 
	 */
	private class DownloadTask extends AsyncTask<String, Void, String> {

		// Downloading data in non-ui thread
		@Override
		protected String doInBackground(String... url) {
			// For storing data from web service
			String data = "";

			try {
				// Fetching the data from web service
				data = downloadUrl(url[0]);
			} catch (Exception e) {
				Log.e("backgroud task", e.toString());
			}
			return data;
		}

		@Override
		protected void onPostExecute(String result) {

			super.onPostExecute(result);

			ParserTask parserTask = new ParserTask();

			// Invokes the thread for parsing the JSON data
			parserTask.execute(result);
		}

	}

	/**
	 * Class parser google place to json format
	 * 
	 * @author Sparkle (' - ')
	 * 
	 */
	private class ParserTask extends
			AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {

		// Parsing the data in non-ui thread
		@Override
		protected List<List<HashMap<String, String>>> doInBackground(
				String... jsonData) {

			JSONObject jObject;
			List<List<HashMap<String, String>>> routes = null;

			try {
				jObject = new JSONObject(jsonData[0]);
				DirectionJSONParser parser = new DirectionJSONParser();

				// Starts parsing data
				routes = parser.parse(jObject);
			} catch (Exception e) {
				Log.e("error", e.getMessage());
			}

			return routes;
		}

		@Override
		protected void onPostExecute(List<List<HashMap<String, String>>> result) {

			super.onPostExecute(result);
			ArrayList<LatLng> points = null;
			PolylineOptions lineOptions = null;
			String distance = "";
			String duration = "";

			// Traversing through all the routes
			for (int i = 0; i < result.size(); i++) {
				points = new ArrayList<LatLng>();
				lineOptions = new PolylineOptions();

				// Fetching i-th route
				List<HashMap<String, String>> path = result.get(i);

				// Fetching all the points in i-th route
				for (int j = 0; j < path.size(); j++) {
					HashMap<String, String> point = path.get(j);

					if (j == 0) { // Get distance from the list
						distance = (String) point.get("distance");
						continue;
					} else if (j == 1) { // Get duration from the list
						duration = (String) point.get("duration");
						continue;
					}

					double lat = Double.parseDouble(point.get("lat"));
					double lng = Double.parseDouble(point.get("lng"));
					LatLng position = new LatLng(lat, lng);

					points.add(position);
				}

				// Adding all the points in the route to LineOptions
				lineOptions.addAll(points);
				lineOptions.width(9);
				lineOptions.color(Color.BLUE);

			}

			txtDistance_time.setText(distance + ", Duration: " + duration);

			String[] temp = distance.split(" ");
			Double giacuoc = mTinhGiaCuoc(Double.parseDouble(temp[0].trim()));
			txtCost.setText(giacuoc.toString() + " VNĐ");

			// Drawing polyline in the Google Map for the i-th route
			mMap.addPolyline(lineOptions);
		}

	}

	/**
	 * Calculator cost taxi
	 * 
	 * @param distance
	 * @return
	 */
	private double mTinhGiaCuoc(double distance) {
		double giacuoc = getGiaMoCua();
		distance = distance - 1;
		if (distance > 0 && distance <= 30) {
			giacuoc += distance * getGiaPhamVi30Km();
		}
		if (distance > 30) {
			giacuoc += 30 * getGiaPhamVi30Km() + (distance - 30)
					* getGiaTren30Km();
		}
		return giacuoc;

	}

	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position,
			long id) {
		String tenHangTaxi = spnHangTaxi.getSelectedItem().toString();
		addItemsLoaiXe(tenHangTaxi);
	}

	@Override
	public void onNothingSelected(AdapterView<?> parent) {
	}

	private void addItemsLoaiXe(String tenHang) {

		spnLoaiXe = (Spinner) findViewById(R.id.spnLoaiXeCost);
		sqlitedB = openOrCreateDatabase(MainActivity.pathSQLite, MODE_PRIVATE,
				null);
		Cursor curSor = null;
		String sql = "select LoaiXe.TenLoai from LoaiXe, HangTaxi where HangTaxi.ID_HangTaxi = LoaiXe.ID_HangTaxi and HangTaxi.TenHang = '"
				+ tenHang + "'";
		curSor = sqlitedB.rawQuery(sql, null);
		arrListLoaiXe = new ArrayList<String>();
		curSor.moveToFirst();
		while (!curSor.isAfterLast()) {
			String data = curSor.getString(0);
			arrListLoaiXe.add(data);
			curSor.moveToNext();
		}
		curSor.close();

		ArrayAdapter<String> adapterLx = new ArrayAdapter<String>(this,
				android.R.layout.simple_spinner_item, arrListLoaiXe);
		adapterLx
				.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spnLoaiXe.setAdapter(adapterLx);
	}

	private double getGiaMoCua() {
		String LoaiXe = spnLoaiXe.getSelectedItem().toString();
		String Hangxe = spnHangTaxi.getSelectedItem().toString();
		String sql = "select GiaCuoc.GiaMoCua from LoaiXe, GiaCuoc, HangTaxi where LoaiXe.ID_HangTaxi = HangTaxi.ID_HangTaxi and LoaiXe.ID_Gia = GiaCuoc.ID_Gia and LoaiXe.TenLoai = '"
				+ LoaiXe + "' and HangTaxi.TenHang = '" + Hangxe + "'";
		Cursor curSor = sqlitedB.rawQuery(sql, null);
		curSor.moveToFirst();
		double gia = curSor.getDouble(0);

		return gia;

	}

	private double getGiaPhamVi30Km() {
		String LoaiXe = spnLoaiXe.getSelectedItem().toString();
		String Hangxe = spnHangTaxi.getSelectedItem().toString();
		String sql = "select GiaCuoc.GiaPhamVi30Km from LoaiXe, GiaCuoc, HangTaxi where LoaiXe.ID_HangTaxi = HangTaxi.ID_HangTaxi and LoaiXe.ID_Gia = GiaCuoc.ID_Gia and LoaiXe.TenLoai = '"
				+ LoaiXe + "' and HangTaxi.TenHang = '" + Hangxe + "'";
		Cursor c = sqlitedB.rawQuery(sql, null);
		c.moveToFirst();
		double gia = c.getDouble(0);
		return gia;

	}

	private double getGiaTren30Km() {
		String LoaiXe = spnLoaiXe.getSelectedItem().toString();
		String Hangxe = spnHangTaxi.getSelectedItem().toString();
		String sql = "select GiaCuoc.GiaTren30Km from LoaiXe, GiaCuoc, HangTaxi where LoaiXe.ID_HangTaxi = HangTaxi.ID_HangTaxi and LoaiXe.ID_Gia = GiaCuoc.ID_Gia and LoaiXe.TenLoai = '"
				+ LoaiXe + "' and HangTaxi.TenHang = '" + Hangxe + "'";
		Cursor c = sqlitedB.rawQuery(sql, null);
		c.moveToFirst();
		double gia = c.getDouble(0);
		return gia;

	}

}
